Part VIII
Advanced MFC

In This Part

  Inside the Registry 1159
  Writing and Using DLLs 1179
  Creating Custom Wizards 1199

Chapter 32
Inside the Registry

by K. David White

In This Chapter

  Registry Usage 1161
  The Registry Structure 1163
  Programmatic Control of the Registry 1164
  The Registry Sample Application 1167
  A Word About Wrapping the Registry Functions 1176
  A Word About Installation 1177

If you are looking for information regarding wedding registries, you’ve come to the wrong place! This chapter discusses a commonly overlooked mechanism available in Windows that is very important to the commercial success of your application: the Windows Registry.

If you are somewhat familiar with the Registry, you might be asking what a chapter about the Windows Registry is doing in a book about MFC programming? Don’t you want to get “under the covers” of MFC here?

Good question! Typically, you see this topic covered in topic-specific books. What I’ve noticed is that this topic is usually covered from a system administration viewpoint, with only passing mention of the API. I have seen some very good articles on the Registry in different magazines, but they only scratch the surface. Most authors and publishers simply feel that the Registry is a peripheral topic not directly related to programming. Most bookstores place a Registry book on the Operating System shelf!

Many moons ago, when I started developing Windows applications, I was a veteran “newbie” to the Windows world, not paying attention to the use of INI files and (later) the Registry. The primary reason for this was that I was reading and relying on programming books (such as this one) to provide me with the information that I needed. Coming from a different operating system (VMS) background (thus the veteran status), I didn’t get to know the operating system components very well before jumping in and developing an application. It wasn’t long before I came face to face with the installation “monster” that forced me to learn the Registry. When I realized how easy it was, I decided to investigate further.

In the not too distant past, Windows applications relied on ASCII-based files to store important information. These files came in the form of *.INI files and were usually stored in either the application’s install directory or in the Windows system directory.


Note:  

Before the method of using INI files, Microsoft used the infamous CONFIG.SYS and AUTOEXEC.BAT (which are still in use). Applications had to maintain their own configuration files. Then along came the system-level INI files. These were PROGMAN.INI, SYSTEM.INI, WIN.INI, and CONTROL.INI.


This was fine as long as the application wasn’t upgraded or moved. These files were easy to change, which gave system administrators a quick-fix method for correcting operating system and application problems. However, this flexibility would many times come back to haunt the administrator. “Easy to fix, easy to break.”

Microsoft, with the release of Windows 3.1, created the Registry. Remarkably, this creation, although simple, has created much confusion and frustration among software developers. In this chapter, you will develop a better understanding of what the Registry is for and how to use it effectively.

What this chapter is not, however, is an in-depth guide to optimizing the Registry to make Windows NT or Windows 95/98 more efficient. This chapter looks at the Registry from the application’s point of view.

Registry Usage

Imagine an application that requires no external direction as to where to run, where to display its interface, what to display on its interface, and so on. You are wondering how an application might “know” about these things without some sort of initialization/remembrance mechanism. One method to store important initialization and state data would be to put it into flat files that the application would read in at startup. These files, commonly called INI files, were widely used, but they are not without their problems:

  Files are sometimes deleted—In many cases, the INI files would accidentally be deleted. You can imagine the problems then!
  Files are sometimes moved—Files also have a tendency to get moved, thereby creating a situation in which the application can’t find the file.
  File versioning problems—I have run into situations where an application’s INI file would not be updated with an upgrade of the application. This happened much more frequently than most developers would like to admit, but it’s something simple to overlook.

Although this list is not complete, you can readily see that the system of maintaining configuration in flat files can quickly run amuck.

Enter the Registry. Originally, the Registry was developed to assist the system administrator in controlling, configuring, and optimizing the Windows operating system. Although that is its primary purpose today, many applications also use it for a plethora of configuration and state information. Many developers believe that the Registry shouldn’t really be used for GUI-related items, but what better way to save important interface information when the application is shut down?


Note:  

Of course, there are limitations to what can be stored in the Registry. The Registry is a file system, and the larger those files get, the longer the Windows operating system takes to boot. There is also a size boundary to the Registry that is operating system-dependent. With this in mind, you might want to limit the information stored. Stick with important configuration and state information, and store buffered data to a file.


I will define some terms here relating to the usage of the Registry.

Configuration

Configuration data is that data that defines not only the operating system runtime parameters, but also the runtime information for applications. The Registry is perfect for defining items such as background color, screen size and location, number of users, and COM property data. Sticking this information away in the Registry whenever an application exits makes it easy to restore at the next startup.

Services Information

You might be thinking that information about a service would fall under configuration or even state, but services are different from user applications. What sets the service apart from other applications is that the interface is normally handled through the Control Panel. Services generally don’t have a user interface; therefore, certain information can only be maintained using flat files or the Registry.

State

State is commonly referred to in programming circles as the point in the programmatic flow that maintains a constant definition. In simpler terms, programmatic flow has steps involved in completion of the algorithm. A state is simply the condition of the data at a defined step. Many control applications are nothing more than state machines, where the application’s state defines the step in the control flow. The Registry lends itself to managing state data for not only the operating system, but also any application.



User Preferences

I have yet to meet a computer user or developer who likes to use the computer exactly the same way as another does. Everyone is different; it’s a fact of life! The Registry provides a placeholder to store user preferences. You might think that applies to operating system preferences, but if you expand your thinking, you can quickly see the benefit for multiuser applications.

The Registry Structure

You’ve learned a little about what the Registry is used for, but before you jump into it programmatically, take a quick look at the structure. Figure 32.1 shows a screen shot of the Registry on a Windows 95 system (my home system).


Figure 32.1  The Registry structure appears to be similar to a file structure.

The Registry is a file. However, through the Registry editor (RegEdt32 and RegEdit for Windows NT and RegEdit for Windows 95/98), it appears as a file system where the keys are displayed as directories and files, and the values are displayed as what is in the file. It is this key/value pair that provides the strength of the Registry. In this sense, it further appears that the Registry is an indexed database or a unique hash table. This, of course, is partially correct. To access data in the Registry, you look it up through its key. Provide the key, and you can set and get the associated value for that key.

Values stored in the Registry typically take the form of strings, compound strings, doubles, and binary data. A string value is made up of a C-style null-terminated string. Compound strings are several null-terminated strings appended together, with another terminator on the end. Doubles are self-explanatory, and binary data can be about anything. As you can see, this is a fairly open mechanism for storing configuration and state data.

Now that you know what kind of data is put into the Registry, the question that remains is where to store the data.


Note:  

A valuable source of information regarding the where question is the “Windows 95 Application Setup Guidelines for Independent Software Vendors” located on the MSDN CD-ROM or MSDN online (http://msdn.microsoft.com/developer/).


The first time I used RegEdit to modify a Registry, I was struck with confusion. The naming system appeared to be Greek. All the root folders started with HKEY, which I didn’t realize was nothing more than a handle to a key. In this case, an HKEY is a handle to the “root” keys of the Registry structure.

Let’s take a look at these keys:

  HKEY_CLASSES_ROOT—This key structure is taken from HKEY_LOCAL_MACHINE\SOFTWARE\Classes and primarily provides compatibility for 16-bit software. From the application’s point of view, you will store file information in this area.
  HKEY_CURRENT_USER—This is where the user-specific data goes. Many applications are single-user, but many can use this key to store user preferences.
  HKEY_LOCAL_MACHINE—This is considered a major key. It stores information about the operating system and the hardware, as well as all the pertinent application data that the operating system needs.
  HKEY_USERS—This is also a major key and is officially the parent of the HKEY_CURRENT_USER key. However, you will notice that the Registry structure puts these two on the same level, and that is done simply for maintainability. This root key stores user profiles for all users on the system.
  HKEY_CURRENT_CONFIG—This is a subkey of HKEY_LOCAL_MACHINE and is used to store information about the current running configuration.
  HKEY_DYN_DATA—Dynamic data store. This is a scratch area for the operating system to store performance and other runtime data.

So what is it that you are looking at when you see the value portion of the key/value pair? The value portion itself is sometimes referred to as a name-value entity. There are essentially three parts to the value: a name for the value, the value associated with that name, and its datatype. Throughout this chapter, however, I will refer to it simply as the value.

Programmatic Control of the Registry

The preceding section discusses the structure, and some of you might already be somewhat familiar with the Registry from previous experience (and hopefully good guidance). Before looking at what MFC provides and how you can expand it, let’s take a quick tour of the Registry API provided by Windows.

The Registry API

Table 32.1 lists a portion of the functions available for manipulating Registry data. More information is provided in the MSDN libraries, and in many other books, but I will pick a few important ones and expand them for my purposes.

Table 32.1 Registry API Functions

API Function Description/Notes

RegOpenKey Opens a key. Pass in the root HKEY and the name of the key to open, and the resultant HKEY is returned as the third parameter.
RegCreateKey Same as RegOpenKey, except that it will create the key if the specified key doesn’t exist.
RegCloseKey Closes a key previously opened by RegOpenKey or RegCreateKey. Releases the handle to the key.
RegDeleteKey Deletes the key from the Registry. (Will not delete the root key. On Windows 95/98, all child keys will also be deleted. On Windows NT, the key to be deleted must not have any children, or a failure is returned.)
RegDeleteValue Deletes the value associated with a key and not the key itself.
RegEnumKey Provides a way to enumerate children of a specified key (RegEnumKey is provided to support Windows 3.1 programming. Use RegEnumKeyEx).
RegEnumValue Provides a way to enumerate all the values of a specified key.
RegFlushKey Writes all the information about an open key back to the Registry.
RegLoadKey Loads a key from a REG file to the Registry, writing all the information saved to the file.
RegSaveKey Saves a key and its value data to a file (usually a REG file).
RegNotifyChangeKeyValue Notifies the caller that value information has changed for the specified key.
RegQueryInfoKey Provides a way to determine child key information, given a root key.



The application at the end of this chapter deals with setting and deleting keys within the application’s configuration data, but first take a quick look at what MFC does for you.

Look inside CWinApp and you will find a member function called SetRegistryKey(). This function takes a single parameter, a string value that will be placed in HKEY_CURRENT_USER\Software\(company name)\(application name)\. In this example, the (company name) was defined as “SAMS MFC Unleashed”, and the application name is RegSamp. A Settings subkey will also be created by the MFC framework. You will use this in this chapter’s example.

At this point, you might be wondering where in the application the SetRegistryKey() function is called. The framework also takes care of this when you use the CWinApp functions GetProfileInt(), SetProfileInt(), GetProfileString(), and SetProfileString().

Let’s take a closer look. Listing 32.1 is from the InitInstance routine. This is standard MFC boilerplate code.

Listing 32.1 Standard Boilerplate Code


// Change the Registry key under which your settings are stored.
    // TODO: You should modify this string to be something appropriate
    // such as the name of your company or organization.
    SetRegistryKey(_T(“SAMS MFC Unleashed”));

    LoadStdProfileSettings();  // Load standard INI file options
                               // (including MRU)

From this, MFC will create the following Registry key:

HKEY_CURRENT_USER\Software\SAMS MFC Unleashed)\RegSamp

MFC will create a Settings child key by default. This enables you to use Get/SetProfileInt() and Get/SetProfileString() to manipulate the Settings child key. MFC makes Registry programming a snap by enabling you to use a single function call to define settings for the application. For example, you’ll find this line of code in the RegSamp sample application:

// Change the Registry key under which your settings are stored.
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization.
SetRegistryKey(_T(“SAMS MFC Unleashed”));

LoadStdProfileSettings();  // Load standard INI file options
                           // (including MRU)

In the sample application, you are saving the left coordinate of your window.


Tip:  

A common mistake is to use CWnd::GetWindowRect() to return the window coordinates, but this really doesn’t return window state information. Use CWnd::GetWindowPlacement() instead. This function uses the WINDOWPLACEMENT structure and will return the window’s current state, which you can then save to a key.


You are probably noticing that MFC provides a fairly easy mechanism for manipulating the Registry for your application, but you should also notice that this might be somewhat limiting. Your application might need to define child keys under different root keys than that of HKEY_CURRENT_USER.

MFC provides no clean way to do this, so you have to use the Registry API. One nice thing about MFC is that you are not restricted to a purely MFC framework when implementing an MFC application.


Note:  

If you are an MFC purist, you might decide to create an extension MFC class that “opens” up the remainder of the Registry root keys to your application. This is a good thing, but because you want to get to the lower level, this chapter will leave that exercise to your design prowess.


The best way to expand your knowledge of the Registry API is to jump in and do a sample application.

The Registry Sample Application

The RegSamp application is fairly simplistic in that it does nothing other than enable the user to create, modify, and delete keys. You will notice from the code in Listing 32.2 that it takes a lot of work to do something so simple. This is primarily because the API is designed to access the Registry at the lowest level.

The Registry Key Editor Dialog

Figure 32.2 is the Registry Key Editor dialog for the RegSamp sample application. RegSamp is an SDI application that contains only the Registry editing feature available from the File menu.


Figure 32.2  The RegSamp Registry Key Editor dialog.

The Registry structure for this application looks like this:

HKEY_LOCAL_MACHINE\Software\SAMS MFC Unleashed\RegSamp\Settings
HKEY_CURRENT_USER\Software\SAMS MFC Unleashed\RegSamp\Settings

Notice the radio button to select the parent path.

The first edit box control is for entering the path information for the child key (commonly referred to as the subkey definition).

The second edit box is for entering the value name to be created/deleted under the subkey.

The third edit box is for entering the value string associated with the value name.


Note:  

I’ve limited the editing to string values. The code could be easily modified/extended to test for datatypes. My aim is to show the process of managing the keys, not necessarily the information contained within the keys.

In the interest of security and protecting the system, the code will limit the user to only the application-specific subkey of HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER. You can quickly see where this functionality could destroy important information.




Creating a New Key

The user creates a new key by selecting the root key and entering the subkey. The user then selects the name of the value that he or she will be associating with the subkey, and then the value string itself. When this is done, the user will select the Create SubKey button.

Let’s take a closer look at this code in Listing 32.2.

Listing 32.2 The OnCreateSubKey() Function


/********************************************************************
 *      User has selected to create a subkey off of settings        *
 *      *NOTE*                                                      *
 *      This application dialog can easily be modified to create    *
 *      subkeys that are not a child of the SETTINGS subkey         *
 *      MFC defaults to this key, but notice the SOFTWARE_KEY_TEXT  *
 *      declaration at the beginning of this code...                *
 ********************************************************************/
void CRegEditor::OnCreateSubkey()
{
    LONG    lnRes;
    HKEY    hMyKey;
    HKEY    hNewKey;

    DWORD dwDisp;

    UpdateData(TRUE);   //Get your Strings
    CString szTempString;

    switch(m_iRootSelected)
    {
        case 0:

            lnRes = RegOpenKeyEx(   HKEY_LOCAL_MACHINE,
                                    SOFTWARE_KEY_TEXT,
                                    0L,KEY_WRITE,&hMyKey    );
            if (ERROR_SUCCESS == lnRes)
            {
                lnRes = RegCreateKeyEx( hMyKey,
                                 m_strSubKey,
                             0,
                             NULL,
                             REG_OPTION_NON_VOLATILE,
                             KEY_ALL_ACCESS,
                             NULL,
                             &;hNewKey,
                             &;dwDisp);

                if (ERROR_SUCCESS != lnRes)
                {
                    // Had an error creating the key.
             if (ERROR_ACCESS_DENIED == lnRes)
                    {
                        // Not an administrator on this machine...
                        AfxMessageBox(“You must be an administrator”,
                                    MB_OK|MB_ICONEXCLAMATION,-1);

             }
            }
            }
            lnRes = RegCloseKey(hMyKey);
            break;

        case 1:

            lnRes = RegOpenKeyEx(   HKEY_CURRENT_USER,
                                    SOFTWARE_KEY_TEXT,
                                    0L,KEY_WRITE,&hMyKey    );
            if (ERROR_SUCCESS == lnRes)
            {
                lnRes = RegCreateKeyEx( hMyKey,
                                 m_strSubKey,
                             0,
                             NULL,
                             REG_OPTION_NON_VOLATILE,
                             KEY_ALL_ACCESS,
                             NULL,
                             &;hNewKey,
                             &;dwDisp);
                if (ERROR_SUCCESS != lnRes)
                {
                    // Had an error creating the key.
                    if (ERROR_ACCESS_DENIED == lnRes)
                    {
                        // Not an administrator on this machine...
                        AfxMessageBox(“You must be an administrator”,
                                        MB_OK|MB_ICONEXCLAMATION,-1);
                    }
                }
            }
            lnRes = RegCloseKey(hMyKey);
            break;
    }

    unsigned char szKeyValue[MAX_KEY_VALUE];
    lstrcpy((char *)szKeyValue,m_strValue);

    lnRes = RegSetValueEx(hNewKey,
                    m_strValueName,
                    0,
                    REG_SZ,
                    szKeyValue,
                    MAX_KEY_VALUE);
    if (ERROR_SUCCESS != lnRes)
    {
        // Error writing to Registry, so close key and throw an exception
        RegCloseKey(hNewKey);
    }

}

It takes quite a bit of work just to create a new subkey. You were probably thinking that all you had to do was enter the parent key path, the new subkey name and any values, and presto! Unfortunately, it is not that easy. There are good reasons for going through the steps that you do. Think of the Registry as a type of database. For security purposes, you would want to open your parent key (reserve it). When you have the handle to your parent, you can create the new subkey. If you didn’t reserve the parent key, and another application were to create a subkey for that same parent, your information wouldn’t match or might invalidate the previous operation. Many installer scripts/applications create many keys directly off the root keys. The root key has to be reserved for this creation so that another application won’t be able to change the substructure for the root key. This should never happen, but better safe than sorry.

Notice the RegCreateKeyEx function call. Important things to remember here are the REG_OPTION_NON_VOLATILE and the KEY_ALL_ACCESS. The REG_OPTION_NON_VOLATILE is the default options settings for key creation, but it’s a good idea to include it here for readability. Following is a table of available options:

  REG_OPTION_NON_VOLATILE (default)—Indicates that the key is not volatile. The information is kept in a file. This allows it to be available when the system is restarted.
  REG_OPTION_VOLATILE—Indicates that the key is volatile. Is only loaded in memory.
  REG_OPTION_BACKUP_RESTORE—If this is defined, it will ignore the access mask and attempt to open the key for backup and restore functions.

The KEY_ALL_ACCESS parameter for the CreateKey function is basically an access privilege mask that is defined for the key. KEY_ALL_ACCESS basically opens up the entire world to your key.

Here is a simplified list of access masks:

  KEY_ALL_ACCESS—Provides global access to the key. Combination of KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, KEY_CREATE_LINK, KEY_SET_VALUE, and KEY_CREATE_SUB_KEY.
  KEY_WRITE—Write access to the key.
  KEY_READ—Read access to the key.
  KEY_CREATE_LINK—Access to create a symbolic link for the key.
  KEY_CREATE_SUBKEY—Access to create a subkey to an open key.
  KEY_EXECUTE—Read access to the key.
  KEY_NOTIFY—Permission to change the notification information for a key.
  KEY_SET_VALUE—Access to set the value for an open key.
  KEY_QUERY_VALUE—Access to query a subkey for its value information. Valuable access to have if you have to enumerate keys.
  KEY_ENUMERATE_SUB_KEYS—Access to enumerate subkeys.


Tip:  

When opening keys for creating subkeys and other functions, it is better from a performance and security standpoint to limit this mask to KEY_WRITE, KEY_SET_VALUE, and KEY_READ privileges. If you are creating a new name/value pair for a key, open the key with KEY_WRITE. When changing the value of a name/value pair, use the Key_SET_VALUE.



Note:  

Notice that the parent key is predefined for this sample application to be SOFTWARE\SAMS MFC Unleashed\RegSamp\Settings. The dialog then enables the user to open a subkey off this parent. This dialog/code will enable the user to open subkeys that are several levels down from this parent, but the subpaths must be defined.

For example, if the user wants to add an Authorize subkey and then a Priority subkey to the Authorize key, enter the path as Authorize\Priority. Don’t forget to enter the name/value pair!

The same can be done for deleting the keys.




Deleting a Key

In some instances, a key might no longer be needed. Using the dialog, the user can remove the key. The user enters the key that he or she wants to delete in the SubKey edit box. The user then selects the Delete SubKey button to activate the following code in Listing 32.3:

Listing 32.3 The OnDeleteSubKey() Function


/********************************************************************
 *      Prior to deleting a key, you need to open its parent..      *
 *      This is done by going to the Settings dependent on what     *
 *      was selected on the dialog.                                 *
 ********************************************************************/
void CRegEditor::OnDeleteSubkey()
{
    LONG    lnRes;
    HKEY    hMyKey;

    UpdateData(TRUE);   //Get your Strings
    CString szTempString;

    switch(m_iRootSelected)
    {
        case 0:

            lnRes = RegOpenKeyEx(   HKEY_LOCAL_MACHINE,
                                    SOFTWARE_KEY_TEXT,
                                    0L,KEY_WRITE,&hMyKey    );
            if (ERROR_SUCCESS == lnRes)
            {
                lnRes = RegDeleteKey(hMyKey,m_strSubKey);
                if (ERROR_ACCESS_DENIED == lnRes)
                {
                    // Not an administrator on this machine...
                    AfxMessageBox(“ACCESS
                   ÄDENIED”,MB_OK|MB_ICONEXCLAMATION,-1);
                }
                if (ERROR_FILE_NOT_FOUND == lnRes)
                {
                    // Not an administrator on this machine...
                    AfxMessageBox(“KEY NOT
                    ÄFOUND”,MB_OK|MB_ICONEXCLAMATION,-1);
                }
            }
            lnRes = RegCloseKey(hMyKey);
            break;

        case 1:

            lnRes = RegOpenKeyEx(   HKEY_CURRENT_USER,
                                    SOFTWARE_KEY_TEXT,
                                    0L,KEY_WRITE,&hMyKey    );
            if (ERROR_SUCCESS == lnRes)
            {
                lnRes = RegDeleteKey(hMyKey,m_strSubKey);

                if (ERROR_ACCESS_DENIED == lnRes)
                {
                    // Not an administrator on this machine...
                    AfxMessageBox(“ACCESS
                    ÄDENIED”,MB_OK|MB_ICONEXCLAMATION,-1);
                }
                if (ERROR_FILE_NOT_FOUND == lnRes)
                {
                    // Not an administrator on this machine...
                    AfxMessageBox(“KEY NOT
                    ÄFOUND”,MB_OK|MB_ICONEXCLAMATION,-1);
                }
            }
            lnRes = RegCloseKey(hMyKey);
            break;
    }

}

The RegDeleteKey API function is actually quite simple. After you open the parent key, you can then delete the subkey.

Deleting a Name/Value Pair

This function is quite different from deleting a key. Many times, the key might stick around, but the underlying name/value pairs might change. I personally wouldn’t recommend this practice, but the following code will do just that.

The user selects the root key, enters the subkey, enters a name for the value to remove, and then clicks the Delete Name/Value Pair button to activate the code in Listing 32.4.

Listing 32.4 The OnDeleteSubKey() Function


/********************************************************************
 *      This routine is a little different from the Delete Key      *
 *      routine.  You simply want to get rid of a value.            *
 *      You first have to Open your Settings Key and then the       *
 *      subkey that is contained within the EditBox on the dialog   *
 *      When you have that, you can use the DeleteKey value         *
 ********************************************************************/
void CRegEditor::OnNvDelete()
{
    LONG    lnRes;

    HKEY    hMyKey;
    HKEY    hMySubKey;

    UpdateData(TRUE);   //Get your Strings

    CString szTempString;

    switch(m_iRootSelected)
    {
        case 0:
            lnRes = RegOpenKeyEx(   HKEY_LOCAL_MACHINE,
                                    SOFTWARE_KEY_TEXT,
                                    0L,KEY_WRITE,&hMyKey    );
            if (ERROR_SUCCESS == lnRes)
            {
                lnRes =
                ÄRegOpenKeyEx(hMyKey,m_strSubKey,0L,KEY_WRITE,&;hMySubKey);
                if (ERROR_SUCCESS == lnRes)
                {
                    lnRes = RegDeleteValue(hMySubKey,m_strValueName);

                    if (ERROR_ACCESS_DENIED == lnRes)
                    {
                        // Not an administrator on this machine...
                        AfxMessageBox(“ACCESS
                        ÄDENIED”,MB_OK|MB_ICONEXCLAMATION,-1);
                    }
                    if (ERROR_FILE_NOT_FOUND == lnRes)
                    {
                        // Not an administrator on this machine...
                        AfxMessageBox(“KEY NOT
                        ÄFOUND”,MB_OK|MB_ICONEXCLAMATION,-1);
                    }
                }
            }
            lnRes = RegCloseKey(hMySubKey);
            lnRes = RegCloseKey(hMyKey);
            break;

        case 1:

            lnRes = RegOpenKeyEx(   HKEY_CURRENT_USER,
                                    SOFTWARE_KEY_TEXT,
                                    0L,KEY_WRITE,&hMyKey    );
            if (ERROR_SUCCESS == lnRes)
            {
                lnRes =
                ÄRegOpenKeyEx(hMyKey,m_strSubKey,0L,KEY_WRITE,&hMySubKey);
                if (ERROR_SUCCESS == lnRes)
                {
                    lnRes = RegDeleteValue(hMySubKey,m_strValueName);

                    if (ERROR_ACCESS_DENIED == lnRes)
                    {
                        // Not an administrator on this machine...
                        AfxMessageBox(“ACCESS
                        ÄDENIED”,MB_OK|MB_ICONEXCLAMATION,-1);
                    }
                    if (ERROR_FILE_NOT_FOUND == lnRes)
                    {
                        // Not an administrator on this machine...
                        AfxMessageBox(“KEY NOT
                        ÄFOUND”,MB_OK|MB_ICONEXCLAMATION,-1);
                    }
                }
            }
            lnRes = RegCloseKey(hMySubKey);
            lnRes = RegCloseKey(hMyKey);
            break;
    }

}

Notice the similarity to the DeleteKey function. However, there is a slight difference. When you have the subkey, you have to open it to remove its value. It is a common mistake to forget this simple little step.



A Word About Wrapping the Registry Functions

I’ve talked a little bit about some important functions to give you access to the Registry. However, you have a lot of code to do some pretty simple things. Making generic utility functions to wrap the Registry API would make life easier for developers, but you are working with MFC here! MFC, being C++, lends itself perfectly to creating a wrapper class for the Registry.

As an added bonus, I have expanded the RegSamp application to use a simple CRegKey class. This class is derived from CObject, primarily for serialization benefits in the future. The RegSamp2 application is available on the CD-ROM.

A Word About Installation

Because this chapter’s sample application is simple, installation requirements aren’t discussed. There are several quality installation programs that will properly register an application during its installation. If an application is improperly installed, it might never get properly uninstalled. The operating system, through the Control Panel, provides a way for users/administrators to remove application programs. This is done by way of a shortcut to an uninstall program. Uninstall programs are usually synchronized with the installation program. If you choose to write your own install and uninstall program, follow the few simple rules shown in Table 32.2.

Table 32.2 Installation and Uninstallation Rules

Rule Comment

Put Uninstall info in its place Uninstall information is stored in the HKEY_LOCAL_MACHINE structure.
Keys Created = Keys Deleted Be smart here. If an application creates a key at installation or during runtime, the uninstall must remove it.
Store directory information An application normally resides in its own directory, or a subdirectory of a larger installation. Be sure that your installscript/application removes the files and the directory. If the applications require unique DLL and INI files, store the directory path information for those files.


Note:  

Most commercial installers and uninstallers will perform all the steps shown in Table 32.2. If you are developing your own uninstall program, remember that the reference (usage) count for shared files (DLLs and so on) needs to be decremented when the application is removed. If the reference count for a system-wide shared file reaches zero, the uninstall program should prompt the user to remove it, giving him the option of leaving it on the system.

I have noticed some applications leaving behind remnants in the Registry. This could be due to any number of problems. Most often, this is a case of not informing the deinstall program of every Registry element of an application. This is usually done through the install script by defining the elements that would need to be uninstalled. In a few cases, the developer might intentionally leave DLLs if more than one program can use them. Doing this should not affect the Registry cleanup, unless the DLL is in a direct execution path. In this case, when deinstalling, the user will be prompted to remove a DLL that can be shared by more than one application.


Summary

You’ve just taken a whirlwind tour of a fairly complex API. You were introduced to some of the important API functions and how to use them. Reading one chapter does not an expert make, and I wouldn’t expect you to completely grasp the Registry until you’ve had the opportunity to explore it.

Although this chapter does not give in-depth coverage for the Registry API, you have learned some key points in dealing with the topic. Until more of the Registry API is encapsulated by MFC, you have no alternative but to “get down and dirty” with it. The Registry is a valuable source of state and configuration information for your applications, and as a developer, you should become familiar with it. I strongly recommend that you spend time with RegEdit and learn your Registry. Then take the sample code and expand it to fit your needs. Remember to back up your Registry files before editing the keys, or you might dread the experience!